
#pragma once

extern LIST_ENTRY   g_stOpenedFileList;
extern LIST_ENTRY   g_stAcceptableList;
extern HANDLE       g_hInjectionHandle;
extern HANDLE       g_hInjectionHandleV6;
extern UINT32       g_nAleFlowEstablishedId;
extern UINT32       g_nAleFlowEstablishedV6Id;
extern UINT32       g_nStreamId;
extern UINT32       g_nStreamIdV6;
extern UINT32       g_nDatagramId;
extern UINT32       g_nDatagramIdV6;
extern LIST_ENTRY   g_stPendedPacketsQueue;
extern KEVENT       g_oWorkerEvent;
extern KEVENT       g_oWorkerDoneEvent;
extern BOOLEAN      g_bDriverUnload;
extern PVOID        g_pWorkerThreadObj;
extern NDIS_HANDLE  g_hNetBufferListPool;
extern NDIS_HANDLE  g_hNetBufferPool;
extern PNDIS_GENERIC_OBJECT g_pNdisGenericObj;

WDF_DECLARE_CONTEXT_TYPE(FLOW_DATA);
WDF_DECLARE_CONTEXT_TYPE(ADDRESSES_DESCRIPTOR);

#define HOST_ADDRESS(nOctet1,nOctet2,nOctet3,nOctet4) ((nOctet4&0xFF) + ((nOctet3&0xFF) << 8) + ((nOctet2&0xFF) << 16) + ((nOctet1&0xFF) << 24))

__inline UINT32 hostAddress(
    UINT32 nOctet1,
    UINT32 nOctet2,
    UINT32 nOctet3,
    UINT32 nOctet4
    )
{
    UINT32  nRet;
    nRet = (nOctet4&0xFF) + ((nOctet3&0xFF) << 8) + ((nOctet2&0xFF) << 16) + ((nOctet1&0xFF) << 24);
    return nRet;
}

#define NET_ADDRESS(nOctet1,nOctet2,nOctet3,nOctet4) ((nOctet1&0xFF) + ((nOctet2&0xFF) << 8) + ((nOctet3&0xFF) << 16) + ((nOctet4&0xFF) << 24))

__inline UINT32 netAddress(
    UINT32 nOctet1,
    UINT32 nOctet2,
    UINT32 nOctet3,
    UINT32 nOctet4
    )
{
    UINT32  nRet;
    nRet = (nOctet1&0xFF) + ((nOctet2&0xFF) << 8) + ((nOctet3&0xFF) << 16) + ((nOctet4&0xFF) << 24);
    return nRet;
}

extern const UINT32 c_ulLocalHost;

__inline void push_css(
    context_state* arContextStateStack,
    context_state enNewContextSate
    )
{
    int     i;
    for(i=19;i>0;i--)
    {
        arContextStateStack[i] = arContextStateStack[i-1];
    }
    arContextStateStack[0] = enNewContextSate;
}

void FilterDataCleanup(
    PADDRESSES_DESCRIPTOR pDeviceAddressesDescriptor
    );

KSTART_ROUTINE dnsfilterWorker;
void
dnsfilterWorker(
    __in PVOID  StartContext
    );

NTSTATUS
dnsfilterCoInitialize(PDEVICE_OBJECT deviceObject);

NTSTATUS 
dnsfilterCoRegisterCallouts(PDEVICE_OBJECT deviceObject);

NTSTATUS
dnsfilterCoRegisterCallout(
   IN OUT PDEVICE_OBJECT deviceObject,
   IN  FWPS_CALLOUT_CLASSIFY_FN ClassifyFunction,
   IN  FWPS_CALLOUT_NOTIFY_FN   NotifyFunction,
   IN  FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN FlowDeleteFunction,
   IN  GUID const* calloutKey,
   IN  UINT32 flags,
   OUT UINT32* calloutId
   );

NTSTATUS NTAPI onFiltersChangeNotify(
    __in FWPS_CALLOUT_NOTIFY_TYPE notifyType,
    __in const GUID* filterKey,
    __inout FWPS_FILTER* filter
    );

void NTAPI onAleFlowEstablishedClassify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __out FWPS_CLASSIFY_OUT* classifyOut
    );

void NTAPI onAleFlowEstablishedV6Classify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __out FWPS_CLASSIFY_OUT* classifyOut
    );

void NTAPI onDatagramDataClassify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __out FWPS_CLASSIFY_OUT* classifyOut
    );

void NTAPI onStreamClassify(
    __in const FWPS_INCOMING_VALUES* inFixedValues,
    __in const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
    __inout_opt void* layerData,
    _In_opt_ const void* classifyContext,
    __in const FWPS_FILTER* filter,
    __in UINT64 flowContext,
    __out FWPS_CLASSIFY_OUT* classifyOut
    );

void NTAPI onDnsFlowDeletion(
    __in UINT16 layerId,
    __in UINT32 calloutId,
    __in UINT64 flowContext
    );

void NTAPI clonedDatagramDnsQueryCompletionFn(
  __in     VOID *context,
  __inout  NET_BUFFER_LIST *netBufferList,
  __in     BOOLEAN dispatchLevel
);

void NTAPI allocatedDatagramDnsQueryCompletionFn(
  __in     VOID *context,
  __inout  NET_BUFFER_LIST *netBufferList,
  __in     BOOLEAN dispatchLevel
);

void NTAPI clonedDatagramDnsResponceCompletionFn(
  __in     VOID *context,
  __inout  NET_BUFFER_LIST *netBufferList,
  __in     BOOLEAN dispatchLevel
);

void NTAPI allocatedDatagramDnsResponceCompletionFn(
  __in     VOID *context,
  __inout  NET_BUFFER_LIST *netBufferList,
  __in     BOOLEAN dispatchLevel
);

void NTAPI clonedStreamDnsQueryCompletionFn(
  __in     VOID *context,
  __inout  NET_BUFFER_LIST *netBufferList,
  __in     BOOLEAN dispatchLevel
);

void NTAPI allocatedStreamDnsQueryCompletionFn(
  __in     VOID *context,
  __inout  NET_BUFFER_LIST *netBufferList,
  __in     BOOLEAN dispatchLevel
);

void NTAPI clonedStreamDnsResponceCompletionFn(
  __in     VOID *context,
  __inout  NET_BUFFER_LIST *netBufferList,
  __in     BOOLEAN dispatchLevel
);

void NTAPI allocatedStreamDnsResponceCompletionFn(
  __in     VOID *context,
  __inout  NET_BUFFER_LIST *netBufferList,
  __in     BOOLEAN dispatchLevel
);

void GetStreamData(
    NET_BUFFER_LIST* pNetBufferList,
    BYTE* pDataBuffer,
    UINT32 nDataBufferLength,
    UINT32* pByteCopied
    );
